package com.infonova.product.jtf.blame;

import java.io.File;
import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.infonova.product.jtf.blame.demo.ServiceLocator;
import com.infonova.product.jtf.blame.util.JtfBlameUtil;


public class ClassFinder {

    private Logger logger = LoggerFactory.getLogger(getClass());

    private static final ClassFinder instance = new ClassFinder();

    public static ClassFinder getInstance() {
        return instance;
    }

    private ClassFinder() {
    }

    private File sourceContainer = new File("E:/workspace/blame-test-failure");
    private Map<String, String> fileCache = new HashMap<String, String>();

    /**
     * @param testClazz e.g. "com.infonova.product.jtf.blame.ClassFinder"
     * @return
     */
    public String findSourceFile(String testClazz) {
        return findFile(JtfBlameUtil.toPartPath(testClazz) + ".class");
    }

    /**
     * Returns the first File that matches th part passed.
     * 
     * @param testClazz e.g. "com/infonova/product/jtf/blame/ClassFinder"
     * @return
     */
    public String findFile(String partFilePath) {
        if (fileCache.containsKey(partFilePath)) {
            return fileCache.get(partFilePath);
        }
        String path = findDeep(sourceContainer, partFilePath);

        fileCache.put(partFilePath, path);
        logger.debug("Caching {} with value {}", partFilePath, path);
        return path;
    }

    public String findDeep(File parent, String path) {
        // logger.debug("Looking for {} in {}", path, parent.getPath());
        for (String name : parent.list()) {
            String fileName = parent.getPath() + "/" + name;
            if (fileName.replaceAll("\\\\", "/").contains(path)) {
                return fileName;
            }
            File dir = new File(fileName);
            if (dir.isDirectory()) {
                String result = findDeep(dir, path);
                if (result != null) {
                    return result;
                }
            }
        }
        return null;
    }

    public Class findImplementation(String className) {
        try {
            return ServiceLocator.getInstance().getService(Class.forName(className)).getClass();
        } catch (ClassNotFoundException e) {
            logger.error("Implementation for {} not found.", className);
        }
        return null;
    }

    public String findImplementingSourceFile(String interfaceClass) {
        String implementation = findImplementation(interfaceClass).getName();
        return findSourceFile(implementation);
    }
}
